package aar.test.tessocr.tessOcrUtil;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.os.Environment;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;

import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.RotatedRect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import clx.tessocr.ocreng.R;


/**
 * Created by Sikang on 2017/4/21.
 */

public class CameraView2 extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
    private final String TAG = "CameraView";
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private boolean isPreviewOn;
    //默认预览尺寸
    private int imageWidth = 1920;
    private int imageHeight = 1080;
    //帧率
    private int frameRate = 30;
    private ImageView hintImage;
    private ImageView hintImage2;
    private ImageView hintImage3;
    private ImageView hintImage4;
    private ImageView hintImage5;
    private ImageView hintImage6;
    private ImageView hintImage7;
    private TextImageProcessor processor;

    public CameraView2(Context context) {
        super(context);
        init();
    }

    public CameraView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CameraView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mHolder = getHolder();
        //设置SurfaceView 的SurfaceHolder的回调函数
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        processor = new TextImageProcessor();
    }

    private int ttop;
    public void settt(int top){
        ttop=top;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //Surface创建时开启Camera
        openCamera();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        //设置Camera基本参数
        if (mCamera != null) {
            initCameraParams();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        try {
            release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public boolean isScanning = false;
    private long starTime, endTime;
//    List<Mat> mats;
    List<RotatedRect> rects;


    /**
     * Camera帧数据回调用
     */
    @Override
    public void onPreviewFrame(final byte[] data, final Camera camera) {
        //识别中不处理其他帧数据
        if (!isScanning) {
            isScanning = true;
            new Thread(new Runnable() {
                @Override
                public void run() {

                    try {
                        Log.d("scantest", "-------------Start------------------");
                        starTime = System.currentTimeMillis();
                        //获取Camera预览尺寸
                        Camera.Size size = camera.getParameters().getPreviewSize();
////
//                        int left = (int) (size.width / 2 - getResources().getDimension(R.dimen.x_15dp));
//                        int top = (int) (size.height / 2 - getResources().getDimension(R.dimen.x_60dp));
//                        int right = (int) (left + getResources().getDimension(R.dimen.x_30dp));
//                        int bottom = (int) (top + getResources().getDimension(R.dimen.x_120dp));


//                        int left = (int) (size.width / 2 - getResources().getDimension(R.dimen.x_20dp));
//                        int top = 0;
//                        int right = (int) (left + getResources().getDimension(R.dimen.x_40dp));
//                        int bottom = (int) (top + size.height);

                        Log.d("scantest", "-------------Start------------------==size.width=="+size.width);
                        Log.d("scantest", "-------------Start------------------==size.height=="+size.height);

                        int left = ttop;
                        int top = 0;
                        int right = (int) (left + (50*getResources().getDisplayMetrics().density));
                        int bottom = (int) (top + size.height);



//                        Log.d("scantest", "-------size.height / 2==" + size.height / 2 + "-----size.width / 2==" + size.width / 2 + "------getResources().getDimension(R.dimen.x_20dp)==" + getResources().getDimension(R.dimen.x_20dp) + "-----getResources().getDimension(R.dimen.x_80dp)==" + getResources().getDimension(R.dimen.x_80dp) + "----- getResources().getDimension(R.dimen.x_40dp==" + getResources().getDimension(R.dimen.x_40dp) + "-----------------size.getResources().getDimension(R.dimen.x_160dp)==" + getResources().getDimension(R.dimen.x_160dp));
//
//                        Log.d("scantest", "-------left==" + left + "-----top==" + top + "------right==" + right + "-----bottom==" + bottom + "-----size.width==" + size.width + "-----------------size.height==" + size.height);

                        //将帧数据转为bitmap
                        final YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
                        if (image != null) {

                            ByteArrayOutputStream stream = new ByteArrayOutputStream();
                            image.compressToJpeg(new Rect(left, top, right, bottom), getQuality(size.height), stream);
                            final Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

                            endTime = System.currentTimeMillis();
                            Log.d("scantest", "帧数据转Bitmap: " + (endTime - starTime) + "ms");
                            starTime = endTime;
                            if (bmp == null) {
                                isScanning = false;
                                return;
                            }

                            if (hintImage == null && getTag() != null) {
                                if (getTag() instanceof ImageView)
                                    hintImage = (ImageView) getTag();
                            }




                            final Bitmap ssBitmap = TesseractUtil.rotateToDegrees(bmp, 90);

//                            MainThread.getInstance().
//                                    execute(new Runnable() {
//                                        @Override
//                                        public void run() {
//                                            hintImage.setVisibility(View.VISIBLE);
//                                            hintImage.setImageBitmap(ssBitmap);
//                                        }
//                                    });





                            if (null != ssBitmap) {
//                                mats = new ArrayList<>();


                                Mat bapMat = new Mat();

                                Utils.bitmapToMat(ssBitmap, bapMat);

                                // binary image
                                Mat binary = new Mat();
                                Imgproc.cvtColor(bapMat, binary, Imgproc.COLOR_BGR2GRAY);

                                Mat binarymedianBlur = new Mat();
                                Imgproc.medianBlur(binary, binarymedianBlur, 3);

                                Mat bf = new Mat();
                                Imgproc.bilateralFilter(binarymedianBlur, bf, 12, 24, 6);


                                Mat out = new Mat();
                                Imgproc.adaptiveThreshold(bf, out, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 27, 10.0d);
                                Mat dst=out.clone();
                                Mat dstF=out.clone();

//                                Imgproc.threshold(binary, binary, 150, 255 ,Imgproc.THRESH_BINARY);
//                                grad.release();
                                final Bitmap scanBmp2 = Bitmap.createBitmap(dst.cols(), dst.rows(), Bitmap.Config.ARGB_8888);

                                Utils.matToBitmap(dst, scanBmp2);

                                if (scanBmp2 == null) {
                                    isScanning = false;
                                    return;
                                }

//                                MainThread.getInstance().
//                                        execute(new Runnable() {
//                                            @Override
//                                            public void run() {
//                                                hintImage2.setVisibility(View.VISIBLE);
//                                                hintImage2.setImageBitmap(scanBmp2);
//                                            }
//                                        });


                                Mat element1 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(30, 9));
                                Mat element2 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(24, 4));
                                Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5, 5));


                                Mat outdilate = new Mat();
                                Point p = new Point(-1, -1);
                                Imgproc.dilate(out, outdilate, element2, p, 1);
//
//                                final Bitmap scanBmp3= Bitmap.createBitmap(outdilate.cols(), outdilate.rows(), Bitmap.Config.ARGB_8888);
//                                Utils.matToBitmap(outdilate, scanBmp3);
//                                MainThread.getInstance().
//                                        execute(new Runnable() {
//                                            @Override
//                                            public void run() {
//                                                hintImage3.setVisibility(View.VISIBLE);
//                                                hintImage3.setImageBitmap(scanBmp3);
//                                            }
//                                        });



                                Mat outerode = new Mat();
                                Imgproc.erode(outdilate, outerode, element1, p, 1);

//                                final Bitmap scanBmp4= Bitmap.createBitmap(outerode.cols(), outerode.rows(), Bitmap.Config.ARGB_8888);
//                                Utils.matToBitmap(outerode, scanBmp4);
//                                MainThread.getInstance().
//                                        execute(new Runnable() {
//                                            @Override
//                                            public void run() {
//                                                hintImage4.setVisibility(View.VISIBLE);
//                                                hintImage4.setImageBitmap(scanBmp4);
//                                            }
//                                        });

                                Mat outdilate2 = new Mat();
                                Imgproc.dilate(outerode, outdilate2, element2, p, 1);

//                                final Bitmap scanBmp5= Bitmap.createBitmap(outdilate2.cols(), outdilate2.rows(), Bitmap.Config.ARGB_8888);
//                                Utils.matToBitmap(outdilate2, scanBmp5);
//                                MainThread.getInstance().
//                                        execute(new Runnable() {
//                                            @Override
//                                            public void run() {
//                                                hintImage5.setVisibility(View.VISIBLE);
//                                                hintImage5.setImageBitmap(scanBmp5);
//                                            }
//                                        });


//                                Imgproc.morphologyEx(out, out, Imgproc.MORPH_OPEN, kernel);



                                List<MatOfPoint> contours = new ArrayList<>();
                                Mat hireachy = new Mat();
                                Imgproc.findContours(outdilate2, contours, hireachy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
//
//                                Scalar color = new Scalar(0, 255, 0);
//                                Mat hireachyDrawContours = new Mat();
//                                Imgproc.drawContours(outdilate2,contours,0,color,20,8,hireachyDrawContours,1,new Point(0,0));
//
                                Log.e("MainActivity", "findCard---3333333333333333333333333333333333--contours==" + contours.size());

                                rects=new ArrayList<>();

                                for(int i=0; i<contours.size(); i++) {
                                    org.opencv.core.Rect rect = Imgproc.boundingRect(contours.get(i));
//                                    Imgproc.contourArea(contours.get(i));
                                      double area = Imgproc.contourArea(contours.get(i));
                                    Log.e("MainActivity", "findCard---3333333333333333333333333333333333--area==" + area);

                                    //找到最小矩形，该矩形可能有方向
                                    MatOfPoint matOfPoint=contours.get(i);
                                    MatOfPoint2f matOfPoint2f=new MatOfPoint2f(matOfPoint.toArray());

                                    double epsilon=   0.001* Imgproc.arcLength(matOfPoint2f,true);

                                    Imgproc.approxPolyDP(matOfPoint2f,matOfPoint2f,epsilon,true);

                                      RotatedRect rotatedRectrect =Imgproc. minAreaRect(matOfPoint2f);




                                    // 计算高和宽7
                                      int m_width = rotatedRectrect.boundingRect().width;

                                      int m_height = rotatedRectrect.boundingRect().height;


//                                    Log.e("MainActivity", "findCard---3333333333333333333333333333333333--m_width==" + m_width+"-------------------m_height=="+m_height);

                                    if((m_width> m_height*10)&&m_height>25) {

                                        int x = rotatedRectrect.boundingRect().x;
                                        int y = rotatedRectrect.boundingRect().y;
                                        int width = rotatedRectrect.boundingRect().width;
                                        int height = rotatedRectrect.boundingRect().height;

                                        Log.e("MainActivity","findCard---444444444444--x=="+x+"----------y=="+y+"------------------width=="+width+"------------height=="+height);


                                          if(((y+height)<bapMat.rows())&&((x+width)<bapMat.cols())){
                                              Scalar color = new Scalar(255, 255, 255);
                                              Imgproc.rectangle(dst,new Point(x,y),new Point(x+width,y+height),color,8);
                                              rects.add(rotatedRectrect);
                                          }



                                    }



//                                    Scalar color = new Scalar(0, 255, 0);
//                                    Mat hireachyDrawContours = new Mat();
//                                    Imgproc.drawContours(dst,contours,i,color,10,8,hireachyDrawContours,1,new Point(0,0));

                                }


//                                final Bitmap scanBmp6= Bitmap.createBitmap(dst.cols(), dst.rows(), Bitmap.Config.ARGB_8888);
//                                Utils.matToBitmap(dst, scanBmp6);
//                                MainThread.getInstance().
//                                        execute(new Runnable() {
//                                            @Override
//                                            public void run() {
//                                                hintImage6.setVisibility(View.VISIBLE);
//                                                hintImage6.setImageBitmap(scanBmp6);
//                                            }
//                                        });


//                                mats = processor.findCardNumBlock2(bapMat);

                                if (null != rects && rects.size() > 0) {

                                    for (int i = 0; i < rects.size(); i++) {


                                        int x = rects.get(i).boundingRect().x-3;
                                        if(x<0){
                                            x=0;
                                        }
                                        int y = rects.get(i).boundingRect().y-3;
                                        if(y<0){
                                            y=0;
                                        }
                                        int width = rects.get(i).boundingRect().width+5;
                                        if(width<0){
                                            width=0;
                                        }
                                        int height = rects.get(i).boundingRect().height+5;
                                        if(height<0){
                                            height=0;
                                        }
                                        Log.e("MainActivity","findCard---555555555555555555555555555555555--x=="+x+"----------y=="+y+"------------------width=="+width+"------------height=="+height+"------------------rects=="+rects.size());
                                        org.opencv.core.Rect rect =new org.opencv.core.Rect(x,y,width,height);

                                          Mat caiMat=new Mat(dstF,rect);


                                        final Bitmap scanBmp = Bitmap.createBitmap(caiMat.cols(),caiMat.rows(), Bitmap.Config.ARGB_8888);
//
                                        Utils.matToBitmap(caiMat, scanBmp);
//
//                                        if (scanBmp == null) {
//                                            isScanning = false;
//                                            return;
//                                        }
//
//                                        MainThread.getInstance().
//                                                execute(new Runnable() {
//                                                    @Override
//                                                    public void run() {
//                                                        hintImage7.setVisibility(View.VISIBLE);
//                                                        hintImage7.setImageBitmap(scanBmp);
//                                                    }
//                                                });


//                                        saveMyBitmap(scanBmp,System.currentTimeMillis()+"");



                                        endTime = System.currentTimeMillis();
                                        Log.e("scantest", "图像旋转、二值化、内容过滤: " + (endTime - starTime) + "ms");
                                        starTime = endTime;

                                        //开始识别
                                        TesseractUtil.getInstance().scanNumber(scanBmp, new SimpleCallback() {
                                            @Override
                                            public void response(String result) {
                                                endTime = System.currentTimeMillis();
                                                Log.e("scantest", "内容识别: " + (endTime - starTime) + "ms");
                                                starTime = endTime;

                                                //这是区域内扫除的所有内容
                                                Log.e("scantest", "扫描结果：  " + result);

                                                if (!TextUtils.isEmpty(getTelnum(result.replace(" ", "")))) {
                                                    //检索结果中是否包含手机号
                                                    Log.e("scantest", "手机号码：  " + getTelnum(result));
                                                    if (null != mShowTextListener) {
                                                        mShowTextListener.showText(result);
                                                    }


                                                } else {

//                                                    isScanning = false;
                                                }

//
                                                Log.e("scantest", "-------------End------------------");
                                            }
                                        });
                                    }


                                } else {
                                    isScanning = false;
                                }


                            }

//                            final Bitmap scanBmp = TesseractUtil.getInstance().catchPhoneRect(TesseractUtil.rotateToDegrees(bmp, 90), hintImage, (int) getResources().getDimension(R.dimen.x_15dp));


                        }
                    } catch (Exception ex) {
                        Log.d("scantest", ex.getMessage());
                        isScanning = false;
                    }

                }
            }).start();
        }

    }

    //压缩比例
    private int getQuality(int width) {
        int quality = 100;
        if (width > 480) {
            float w = 480 / (float) width;
            quality = (int) (w * 100);
        }
        return quality;
    }

//
    public void setShowImage(ImageView ima) {
        if (null != ima) {
            hintImage2 = ima;
        }

    }
//
    public void setShowImage3(ImageView ima) {
        if (null != ima) {
            hintImage3 = ima;
        }

    }

    public void setShowImage4(ImageView ima) {
        if (null != ima) {
            hintImage4 = ima;
        }

    }

    public void setShowImage5(ImageView ima) {
        if (null != ima) {
            hintImage5 = ima;
        }

    }

    public void setShowImage6(ImageView ima) {
        if (null != ima) {
            hintImage6 = ima;
        }

    }

    public void setShowImage7(ImageView ima) {
        if (null != ima) {
            hintImage7 = ima;
        }

    }

    /**
     * 保存图片到本地
     */
//    public String saveMyBitmap(Bitmap mBitmap, String fileName) {
//        if (mBitmap == null)
//            return null;
//        File file = null;
//        try {
//            file = new File(  Environment.getExternalStorageDirectory() + "/DCIM/normal/" + fileName+".jpg");
//            if (!file.exists())
//                file.createNewFile();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        FileOutputStream fOut = null;
//        try {
//            fOut = new FileOutputStream(file);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
//
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//
//            }
//        }).start();
//        mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
//        try {
//            fOut.flush();
//            fOut.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//
//        if (file.exists()){
//            return file.getAbsolutePath();
//        }
//
//        return null;
//    }

    public boolean isNumeric(String str) {

        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);

        return isNum.matches();

    }

    /**
     * 获取字符串中的手机号
     */
    public String getTelnum(String sParam) {

        if (sParam.length() <= 0) {
            return "";
        }
//        if (sParam.length() != 11) {
//            return "";
//        }

//        if (!isNumeric(sParam)) {
//            return "";
//        }
//
//        Pattern pattern = Pattern.compile("[1|861][3|5|7|8]\\d{9}$*");
//        Matcher matcher = pattern.matcher(sParam);
//        StringBuffer bf = new StringBuffer();
//        while (matcher.find()) {
//            bf.append(matcher.group()).append(",");
//        }
//        int len = bf.length();
//        if (len > 0) {
//            bf.deleteCharAt(len - 1);
//        }
        return sParam;
    }

    /**
     * 获取字符串中的单号
     */
    public String getOrder(String sParam) {
        if (sParam.length() <= 0)
            return "";
        Pattern pattern = Pattern.compile("\\d{12,}$*");
        Matcher matcher = pattern.matcher(sParam);
        StringBuffer bf = new StringBuffer();
        while (matcher.find()) {
            bf.append(matcher.group()).append(",");
        }
        int len = bf.length();
        if (len > 0) {
            bf.deleteCharAt(len - 1);
        }
        return bf.toString();
    }


    /**
     * Bitmap裁剪
     *
     * @param bitmap 原图
     * @param width  宽
     * @param height 高
     */
    public static Bitmap bitmapCrop(Bitmap bitmap, int left, int top, int width, int height) {
        if (null == bitmap || width <= 0 || height < 0) {
            return null;
        }
        int widthOrg = bitmap.getWidth();
        int heightOrg = bitmap.getHeight();
        if (widthOrg >= width && heightOrg >= height) {
            try {
                bitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
            } catch (Exception e) {
                return null;
            }
        }
        return bitmap;
    }


    /**
     * 图片旋转
     *
     * @param tmpBitmap
     * @param degrees
     * @return
     */
    public static Bitmap rotateToDegrees(Bitmap tmpBitmap, float degrees) {
        Matrix matrix = new Matrix();
        matrix.reset();
        matrix.setRotate(degrees);
        return Bitmap.createBitmap(tmpBitmap, 0, 0, tmpBitmap.getWidth(), tmpBitmap.getHeight(), matrix,
                true);
    }


    /**
     * 摄像头配置
     */
    public void initCameraParams() {
        stopPreview();
        Camera.Parameters camParams = mCamera.getParameters();
        List<Camera.Size> sizes = camParams.getSupportedPreviewSizes();
        for (int i = 0; i < sizes.size(); i++) {
            if ((sizes.get(i).width >= imageWidth && sizes.get(i).height >= imageHeight) || i == sizes.size() - 1) {
                imageWidth = sizes.get(i).width;
                imageHeight = sizes.get(i).height;
//                Log.v(TAG, "Changed to supported resolution: " + imageWidth + "x" + imageHeight);
                break;
            }
        }
        camParams.setPreviewSize(imageWidth, imageHeight);
        camParams.setPictureSize(imageWidth, imageHeight);
//        Log.v(TAG, "Setting imageWidth: " + imageWidth + " imageHeight: " + imageHeight + " frameRate: " + frameRate);

        camParams.setPreviewFrameRate(frameRate);
//        Log.v(TAG, "Preview Framerate: " + camParams.getPreviewFrameRate());

        mCamera.setParameters(camParams);
        //取到的图像默认是横向的，这里旋转90度，保持和预览画面相同
        mCamera.setDisplayOrientation(90);
        // Set the holder (which might have changed) again
        startPreview();
    }

    /**
     * 开始预览
     */
    public void startPreview() {
        try {
            mCamera.setPreviewCallback(this);
            mCamera.setPreviewDisplay(mHolder);//set the surface to be used for live preview
            mCamera.startPreview();
            mCamera.autoFocus(autoFocusCB);
        } catch (IOException e) {
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * 停止预览
     */
    public void stopPreview() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
        }
    }

    /**
     * 打开指定摄像头
     */
    public void openCamera() {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        for (int cameraId = 0; cameraId < Camera.getNumberOfCameras(); cameraId++) {
            Camera.getCameraInfo(cameraId, cameraInfo);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                try {
                    mCamera = Camera.open(cameraId);
                } catch (Exception e) {
                    if (mCamera != null) {
                        mCamera.release();
                        mCamera = null;
                    }
                }
                break;
            }
        }
    }

    /**
     * 摄像头自动聚焦
     */
    Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
        public void onAutoFocus(boolean success, Camera camera) {
            postDelayed(doAutoFocus, 1000);
        }
    };
    private Runnable doAutoFocus = new Runnable() {
        public void run() {
            if (mCamera != null) {
                try {
                    mCamera.autoFocus(autoFocusCB);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    };

    /**
     * 释放
     */
    public void release() {
        if (isPreviewOn && mCamera != null) {
            isPreviewOn = false;
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }


    public interface showTextListener {
        void showText(String tt);

        void getRecBitmap(Bitmap bap);
    }


    public showTextListener mShowTextListener;


    public void setShowTextListener(showTextListener mShowTextListener) {

        this.mShowTextListener = mShowTextListener;

    }










}
